﻿using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using ComponentFactory.Krypton.Toolkit;
using Chimp.Core;
using SharpSvn;
using SharpSvn.UI;
namespace SpaceChimpIDE
{
    public partial class Form1 : KryptonForm
    {
        public static ChimpJointDoc Out;
        public static ChimpJointDoc ActiveDoc = null;
        public Dictionary<ChimpJointDoc, TabPage> Tabs = new Dictionary<ChimpJointDoc, TabPage>();
        public List<ChimpJointDoc> Pages = new List<ChimpJointDoc>();
        public Form1 ( )
        {
            InitializeComponent ( );
            OutBox.Words.Clear();
            OutBox.NewWord("Building",Color.Red,"~",":");
            OutBox.NewWord(":",Color.DarkViolet,"Building","~");
            OutBox.NewWord("App",Color.ForestGreen,"","Running");
            OutBox.NewWord("Running",Color.Crimson,"App","~");
            OutBox.NewWord("Error",Color.Green);
            OutBox.NewWord(":",Color.Firebrick,"Error","~");
            Out = OutBox;
            LoadLastProject();
        }
        public static void ChangeActiveKey(string k)
        {
            if ( ActiveDoc == null ) return;
            ActiveDoc.ChangeKey(k);
        }
        public static void LogMsg(string text)
        {
            Console.WriteLine("Msg:"+text);
            Out.AddText(text+"\n--");

            /// Clipboard.SetText("\n"+text+"\n---------\n");
            //Out.Paste("");

        }
        public static void ErrMsg(string text)
        {
            Out.AddText("Error:" + text + "\n!!");
            //Clipboard.SetText("\nError:"+text+"\n!!!!!!!!\n");
            //Out.Paste("");


        }

        private void kryptonRibbon1_SelectedTabChanged ( object sender, EventArgs e )
        {

        }

        private void newJointToolStripMenuItem_Click ( object sender, EventArgs e )
        {
            NewDoc ( );
            LogMsg("Created new Joint.");
        }

        private void NewDoc ()
        {
          
            ChimpJointDoc jdoc = new ChimpJointDoc ( );
            TabPage tp = new TabPage ( "New Joint" );
            tp.Controls.Add ( jdoc );
            jdoc.Dock = DockStyle.Fill;
            Docs.TabPages.Add ( tp );
            Pages.Add ( jdoc );
            ActiveDoc = jdoc;
            Tabs.Add(ActiveDoc,tp);
        }
        private void pasteToolStripMenuItem_Click ( object sender, EventArgs e )
        {
            if ( ActiveDoc == null ) return;
            ActiveDoc.Paste(Clipboard.GetText());

        }
        public string LastPath ( )
        {
            if (System.IO.File.Exists("LastPath.config"))
            {

                return System.IO.File.ReadAllText("LastPath.config");
            }
            return "";
        }

        public void SetLastPath(string p)
        {
            if ( p == null ) p = "";
            System.IO.File.WriteAllText("LastPath.config",p);
        }
        private void loadJointToolStripMenuItem_Click ( object sender, EventArgs e )
        {
            openFileDialog1.AddExtension = false;
            openFileDialog1.DefaultExt = ".joint";
            openFileDialog1.InitialDirectory = LastPath();
            openFileDialog1.ShowDialog();
            var path = openFileDialog1.FileName;
            if(openFileDialog1.FileName == null || openFileDialog1.FileName=="")
            {
               ErrMsg("Invalid Joint Path.");
                return;
            }
            if ( System.IO.File.Exists ( openFileDialog1.FileName ) )
            {

                LoadDoc(path);
            }else
            {
                ErrMsg("Unable to load Joint.");

            }
        }

        private void LoadDoc(string path)
        {
            NewDoc();
            ActiveDoc.Load(path);
            Tabs[ActiveDoc].Text = path;
            SetLastPath(path);
            Docs.SelectedTab = Tabs[ActiveDoc];
            LogMsg("Loaded Joint:"+path);
        }

        private void saveJointToolStripMenuItem_Click ( object sender, EventArgs e )
        {
            if ( ActiveDoc == null ) return;
            if(ActiveDoc.DocPath!="")
            {
                ActiveDoc.Save();
                LogMsg("Saved "+ActiveDoc.DocPath);

            }else
            {
                SaveDocAs ( );

            }
        }

        private void SaveDocAs ( )
        {
            if(ActiveDoc==null)
            {
                ErrMsg("No active document to save.");
                return;

            }
            saveFileDialog1.DefaultExt = ".joint";
            saveFileDialog1.InitialDirectory = LastPath ( );
            saveFileDialog1.Title = "Select filename for Joint.";
            saveFileDialog1.ShowDialog ( );
            if(saveFileDialog1.FileName.Length<1)
            {
                ErrMsg("Illegal name to save Joint as.");
                return;
            }
            ActiveDoc.DocPath = saveFileDialog1.FileName;
            ActiveDoc.Save ( );
            Tabs[ActiveDoc].Text = ActiveDoc.DocPath;
            SetLastPath(ActiveDoc.DocPath);
            LogMsg("Saved Joint As:"+ActiveDoc.DocPath);
        }
        private void saveJointAsToolStripMenuItem_Click ( object sender, EventArgs e )
        {
            if ( ActiveDoc == null ) return;
            SaveDocAs();
           
        }

        private bool ignoreSel = false;
        private void Docs_SelectedIndexChanged ( object sender, EventArgs e )
        {
            UpdateActiveDoc();
        }

        private void UpdateActiveDoc()
        {
            var si = Docs.SelectedTab;
            foreach(var p in Tabs.Keys)
            {
                var d = Tabs[p];
                if(d==si)
                {
                    ActiveDoc = p;
                    Console.WriteLine("Active Doc:"+ActiveDoc.DocPath);
                }
            }
        }

        private void toolStripSeparator3_Click ( object sender, EventArgs e )
        {

        }

        private void toolStripMenuItem1_Click ( object sender, EventArgs e )
        {
            CloseActiveDoc ( );

        }

        private void CloseActiveDoc ( )
        {
            ignoreSel = true;
            if ( ActiveDoc != null )
            {
                var tp = Tabs[ ActiveDoc ];
                Tabs.Remove ( ActiveDoc );
                Docs.TabPages.Remove ( tp );
                Pages.Remove ( ActiveDoc );
                LogMsg("Closed Joint "+ActiveDoc.DocPath);
            }
            ignoreSel = false;
        }

        private void closeAllJointsToolStripMenuItem_Click ( object sender, EventArgs e )
        {
            foreach(var d in Pages.ToArray())
            {
                ActiveDoc = d;
                CloseActiveDoc();

            }
        }

        private void buildRunToolStripMenuItem_Click ( object sender, EventArgs e )
        {
            CompileAndRun();
        }

        public void CompileAndRun()
        {
            if ( ActiveDoc == null )
            {
                LogMsg("No Joint opened.");
                return;
            }
            if ( ActiveDoc.DocPath == "" )
            {
                SaveDocAs ( );

                return;
            }
            else
            {
                ActiveDoc.Save();
            }
            LogMsg("About to parse/compile&execute...");
            Console.WriteLine("About to Roll Joint...");
            var op = "temp.joint";
            System.IO.File.WriteAllText(op,ActiveDoc.GetText());
            var j = new JointApp(op);
            j.Produce();
            j.Play();
            
            Docs.SelectedTab = VP;
            LogMsg("App Running!");
        }

        private void toolStripButton2_Click ( object sender, EventArgs e )
        {
            LogMsg("Stopping Joint.");
            if(ChimpApp.ActiveState.Count>0)
            {
                ChimpApp.ActiveState[ChimpApp.ActiveState.Count - 1].OnStop();
            }
            ChimpApp.ActiveState.Clear();
            ChimpApp.States.Clear();
            LogMsg("Stopped Joint.");
        }

        private void toolStripButton1_Click ( object sender, EventArgs e )
        {
            CompileAndRun();
        }

        private void toolStripButton3_Click ( object sender, EventArgs e )
        {
            if ( ActiveDoc == null ) return;
            Clipboard.SetText("State NewState\n\n   Event OnStart\n\n\n End\n\n Event OnUpdate\n\n\n    End\n\n Event OnDraw\n\n\n  End\n\nEnd\n\n");
            ActiveDoc.Paste("");
        }

        private void toolStripButton4_Click ( object sender, EventArgs e )
        {
            if ( ActiveDoc == null ) return;
            Clipboard.SetText ( "Transient NewTrans\n\n   Event OnBegin\n\n\n End\n\n Event OnUpdate\n\n\n    End\n\n Event OnDraw\n\n\n  End\n\nEnd\n\n" );
            ActiveDoc.Paste ( "" );
        }

        private void createProjectToolStripMenuItem_Click ( object sender, EventArgs e )
        {
            folderBrowserDialog1.ShowNewFolderButton = true;
            folderBrowserDialog1.Description =
                "Select a (prefably empty) folder to create\nyour new SpaceChimp Project.";
            folderBrowserDialog1.ShowDialog();
            CreateProject(folderBrowserDialog1.SelectedPath);
            // SetLastPath(folderBrowserDialog1.SelectedPath);
        }

        public string ProjectPath
        {
            get { return mProjPath; }
            set { mProjPath = value; SaveLastProject();
                JointSettings.ImportPaths.Clear();JointSettings.RegPath(ProjectPath);
            }
        }

        private string mProjPath = "";

       

        public void SetProject(string p)
        {
            if ( Directory.Exists ( p ) )
            {
                ProjectPath = p;

                LoadProjectDetails();
                UpdateProjectGUI();
                SaveLastProject();
            }else
            {
                LogMsg("Invalid last project, rejected.");
            }
        }
        public void SaveLastProject()
        {
            File.WriteAllText("CurrentProject.info", ProjectPath);

        }
        public void LoadLastProject()
        {
            if ( File.Exists ( "CurrentProject.info" ) )
            {
                SetProject(File.ReadAllText("CurrentProject.info"));
                LoadProjectDetails();
                UpdateProjectGUI();
            }
        }
        public Dictionary<string, bool> TreeLUT = new Dictionary<string, bool>();
        public void UpdateProjectGUI()
        {
            if ( ProjectPath == "" ) return;
            TreeNode root = new TreeNode(ProjectPath);
            ProjTree.Nodes.Clear();
            ProjTree.Nodes.Add(root);
            ProjTree.ShowLines = true;
            ProjTree.ShowPlusMinus = true;
            ProjTree.ShowRootLines = true;
            AddFolderToProjTree(ProjectPath, root);
            SaveProjectDetails();
            root.Expand();
           
          
        }
        public void SaveProjectDetails()
        {
            FileStream fs = new FileStream(ProjectPath + "\\ProjectTree.lut", FileMode.Create, FileAccess.Write);
            BinaryWriter w = new BinaryWriter(fs);
            w.Write(TreeLUT.Keys.Count);
            foreach(var k in TreeLUT.Keys)

            {
                w.Write(k);
                w.Write(TreeLUT[k]);
            }
            w.Flush();
            fs.Flush();
            w = null;
            fs.Close();
            fs = null;
            ProjTree.LabelEdit = true;
        }
        public void LoadProjectDetails()
        {
            if ( File.Exists ( ProjectPath + "\\ProjectTree.lut" ) == false ) return;
            FileStream fs = new FileStream(ProjectPath+"\\ProjectTree.lut", FileMode.Open, FileAccess.Read);
            BinaryReader r = new BinaryReader(fs);
            int lc = r.ReadInt32();
            TreeLUT.Clear();
            for(int i=0;i<lc;i++)
            {
                var k = r.ReadString();
                var b = r.ReadBoolean();
                TreeLUT[k] = b;
            }
            r = null;
            fs.Close();
            fs = null;

        }
        public void AddFolderToProjTree(string f,TreeNode p)
        {
            foreach(var fi in new DirectoryInfo(f).GetDirectories())
            {
                TreeNode nn = new TreeNode(fi.Name);
                nn.Tag = fi.FullName;
                p.Nodes.Add(nn);
                AddFolderToProjTree(fi.FullName, nn);
                if(TreeLUT.ContainsKey(fi.FullName))
                {
                    if(TreeLUT[fi.FullName])
                    {
                        nn.Expand();
                    }
                }else
                {
            
                }
            }
            foreach(var fi in new DirectoryInfo(f).GetFiles())
            {
                TreeNode nn = new TreeNode(fi.Name);
                p.Nodes.Add(nn);
                nn.Tag = fi.FullName;
                

                
            }
        }
        public void CreateProject(string p)
        {
            TreeLUT.Clear();
       
            ProjectPath = p;
            SaveProjectDetails();
            SetProject(p);
            File.WriteAllText(ProjectPath + "\\Main.joint", " ");
            UpdateProjectGUI();
        }

        private void ProjTree_AfterExpand ( object sender, TreeViewEventArgs e )
        {
            if ( e.Node.Tag == null ) return;
            TreeLUT[(string) e.Node.Tag] = e.Node.IsExpanded;
            SaveProjectDetails();
        }

        private void ProjTree_AfterCollapse ( object sender, TreeViewEventArgs e )
        {
            if ( e.Node.Tag == null ) return;
            TreeLUT[(string) e.Node.Tag] = e.Node.IsExpanded;
            SaveProjectDetails();
        }

        private void ProjTree_NodeMouseDoubleClick ( object sender, TreeNodeMouseClickEventArgs e )
        {
            var n = ProjTree.SelectedNode;
            if(TreeLUT.ContainsKey((string)n.Tag))
            {
                
            }else
            {
                if(new FileInfo((string)n.Tag).Extension.ToLower().Contains("joint"))
                {
                    LoadDoc((string)n.Tag);
                }
            }
        }

        private void newJointSourceToolStripMenuItem_Click ( object sender, EventArgs e )
        {
            if(ProjectPath=="")
            {
               ErrMsg("No active project.");
                return;
            }
            File.WriteAllText(ProjectPath + "\\NewJoint.joint", " ");
        //    LoadDoc(ProjectPath+"\\NewJoint.joint");
            UpdateProjectGUI();
            SaveProjectDetails();
        }

        private void kryptonButton1_Click ( object sender, EventArgs e )
        {
            UpdateProjectGUI();
            SaveProjectDetails();
        }

        private TreeNode EditNode = null;
        private void ProjTree_NodeMouseClick ( object sender, TreeNodeMouseClickEventArgs e )
        {
            return;
            if(EditNode!=null && EditNode!=e.Node)
            {
                EditNode.EndEdit(true);
                EditNode = null;
            }
            if(e.Node.IsEditing)
            {
               e.Node.EndEdit(false);
                EditNode = null;
                string nf = (string) e.Node.Tag;
                nf.Replace(new FileInfo(nf).Name, e.Node.ToString());
                File.Copy((string)e.Node.Tag,nf);
                Directory.Delete((string)e.Node.Tag);
                e.Node.Tag = nf;
                UpdateProjectGUI();
                LoadProjectDetails();
               
                return;
            }
            e.Node.BeginEdit();
            EditNode = e.Node;
        }

        private void saveExitToolStripMenuItem_Click ( object sender, EventArgs e )
        {
            foreach(var d in Pages)
            {
                d.Save();
            }
            Environment.Exit(-1);
        }

        private void setProjectToolStripMenuItem_Click ( object sender, EventArgs e )
        {
            folderBrowserDialog1.ShowDialog();
            SetProject(folderBrowserDialog1.SelectedPath);
            LoadProjectDetails();
            UpdateProjectGUI();
            SaveProjectDetails();
        }

        private void Form1_KeyDown ( object sender, KeyEventArgs e )
        {
            if(e.KeyCode == Keys.F5)
            {
                CompileAndRun();
            }
        }

        private void Docs_Selected ( object sender, TabControlEventArgs e )
        {
            UpdateActiveDoc();
        }
        public static class Svn
        {
            public static string SvnUrl = "NotSet";
            public static SvnUrlGetter GetUrl = null;
            public static string LogMsg = "";
        }
        private void checkoutToolStripMenuItem_Click ( object sender, EventArgs e )
        {
            GetSvnUrl();

            //CheckoutProject();
        }

        private void GetSvnUrl()
        {
            if(ProjectPath=="")
            {
                ErrMsg("No open project to check out to. Create one first.");
                return;
            }
            if(Svn.SvnUrl!="NotSet")
            {
                CheckoutProject();
                return;
            }

            if(Svn.GetUrl!=null)
            {
                Svn.GetUrl.Close();
                if ( Svn.GetUrl.IsDisposed == false )
                {
                    Svn.GetUrl.Dispose();
                }
                Svn.GetUrl = null;

            }
            Svn.GetUrl = new SvnUrlGetter();
            Svn.GetUrl.Checkout = true;
            Svn.GetUrl.Owner = this;
            Svn.GetUrl.Show();
        }

        public void RegSvn(SvnClient c)
        {
            c.Progress += new EventHandler<SvnProgressEventArgs> ( c_Progress );
            c.Processing += new EventHandler<SvnProcessingEventArgs> ( c_Processing );
            c.SvnError += new EventHandler<SvnErrorEventArgs> ( c_SvnError );
            c.Committing += new EventHandler<SvnCommittingEventArgs> ( c_Committing );
        }

        void c_Committing ( object sender, SvnCommittingEventArgs e )
        {
            LogMsg("Commiting:"+e.Items.ToString());
        }


        void c_SvnError ( object sender, SvnErrorEventArgs e )
        {
            LogMsg(e.Exception.ToString()+"\n"+e.Exception.InnerException.ToString());
        }

        void c_Processing ( object sender, SvnProcessingEventArgs e )
        {
            LogMsg("Performing:"+e.CommandType.ToString());
        }

        void c_Progress ( object sender, SvnProgressEventArgs e )
        {
            LogMsg(e.Progress+"/"+e.TotalProgress);
        }
        public void CommitProject()
        {
            using ( SvnClient c = new SvnClient ( ) )
            {
              
                var url = new SvnUriTarget ( Svn.SvnUrl );
                SvnUI.Bind ( c, this );
                RegSvn ( c );
                AddFolder(c,ProjectPath);
                SvnCommitResult res;
                SvnCommitArgs args = new SvnCommitArgs();
                args.LogMessage = "SpaceChimpIDE@" + DateTime.Now.ToShortTimeString() + "@" +
                                  DateTime.Now.ToShortDateString();
                args.LogMessage += "\n\n" + Svn.LogMsg;
              
                CommitFile(c, args, ProjectPath);
                //if ( res != null )
                // {
                //   LogMsg ( "Committed revision:" + res.Revision );


//                }
            }
        }
        private void AddFolder(SvnClient c,string p)
        {
            foreach(var f in new DirectoryInfo(p).GetFiles())
            {
                SvnAddArgs a = new SvnAddArgs();
                a.AddParents = false;
                a.Depth = SvnDepth.Empty;
                a.Progress += new EventHandler<SvnProgressEventArgs> ( a_Progress );
                c.Add(f.FullName, a);

            }
            foreach(var f in new DirectoryInfo(p).GetDirectories())
            {
                if(f.Name.ToLower().Contains("svn"))
                {
                    continue;
                }
                AddFolder(c,f.FullName);
            }
        }

        void a_Progress ( object sender, SvnProgressEventArgs e )
        {
            LogMsg("Adding File:" + e.Progress + "/" + e.TotalProgress);
        }
        private SvnCommitResult CommitFile(SvnClient c, SvnCommitArgs args, string pp)
        {
            SvnCommitResult res;
            c.Commit(pp,args, out res );
            return res;
        }

        public void CheckoutProject()
        {
            using(SvnClient c = new SvnClient())
            {
                var url = new SvnUriTarget(Svn.SvnUrl);
                SvnUI.Bind(c,this);
                RegSvn(c);
                SvnUpdateResult res;
                c.CheckOut(url, ProjectPath, out res);
                if(res!=null)
                {
                    LogMsg("Checked out revision:" + res.Revision);
                   

                }
            }
        }

        private void commitToolStripMenuItem_Click ( object sender, EventArgs e )
        {
            GetSvnUrl();
            Svn.GetUrl.Checkout = false;
            Svn.GetUrl.Commit = true;

        }
    }

}
